#include<iostream>
#include"rtp.h"
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<thread>
#pragma comment(lib, "ws2_32.lib")
#pragma warning( disable : 4996 ) // inet_addr 方法已经被遗弃了，直接调用会报错，需要禁用该报错

using namespace std;

// #define H264_FILE_NAME "D:\\code\\VisualStudio\\study\\rtsp-server\\data\\test.h264"
// #define AAC_FILE_NAME "D:\\code\\VisualStudio\\study\\rtsp-server\\data\\test.aac"

#define H264_FILE_NAME "D:\\code\\CLion\\study\\media_stream\\data\\input.h264"
#define AAC_FILE_NAME "D:\\code\\CLion\\study\\media_stream\\data\\input.aac"

// #define H264_FILE_NAME "D:\\data\\video\\demo\\test.h264"
// #define AAC_FILE_NAME "D:\\data\\video\\demo\\test.aac"

#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8554
#define SERVER_RTP_PORT 55532
#define SERVER_RTCP_PORT 55533
// 大多数时候创建buf的字节最大值
#define BUF_MAX_SIZE (1024*1024)

// 创建TCP协议的socket，并返回该socket的文件描述符
 int createTcpSocket()
{
	int sockfd;
	int on = 1;
	// 创建IPV4地址的TCP协议的套接字
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
	{
		return -1;
	}
	// 修改套接字选项，允许地址重用，这样在服务器重启的时候可以避免该端口因为被上次关闭还在占用而无法启动
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
	return sockfd;
}

// 创建UDP协议的socket，并返回该socket的文件描述符
 int createUdpSocket()
{
	int sockfd;
	int on = 1;
	// 创建IPV4地址的UDP协议的套接字
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0)
	{
		return -1;
	}
	// 修改套接字选项，允许地址重用，这样在服务器重启的时候可以避免该端口因为被上次关闭还在占用而无法启动
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
	return sockfd;
}

// 将套接字绑定到指定的ip、port
 int bindSocketAddr(int sockfd, const char* ip, int port)
{
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ip);
	// 将套接字绑定到指定的ip、port
	if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr)) < 0)
	{
		return -1;
	}
	return 0;
}

// 监听客户端的连接，并返回客户端链接时的创建的套接字描述符
 int acceptClient(int sockfd, char* ip, int* port)
{
	int clientfd;
	socklen_t len = 0;
	struct sockaddr_in addr;
	// 初始化结构体
	memset(&addr, 0, sizeof(addr));
	len = sizeof(addr);
	// 监听套接字的连接
	clientfd = accept(sockfd, (struct sockaddr*)&addr, &len);
	if (clientfd < 0)
	{
		return -1;
	}
	// 复制连接上来的客户端的ip、port
	strcpy(ip, inet_ntoa(addr.sin_addr));
	*port = ntohs(addr.sin_port);
	return clientfd;
}

// 处理OPTIONS请求，构建响应数据到result中
 int handleCmd_OPTIONS(char *result, int cseq)
{
	sprintf(result, "RTSP/1.0 200 OK\r\n"
        "CSeq: %d\r\n"
        "Public: OPTIONS, DESCRIBE, SETUP, PLAY\r\n"
		"\r\n",
		cseq);
	return 0;
}

// 处理DESCRIBE请求，构建响应数据到result中
 int handleCmd_DESCRIBE(char* result, int cseq, char* url)
{
	char sdp[500];
	char localIp[100];
	/*
	* 示例url内容： rtsp://127.0.0.1:8554
	* rtsp://%[^:]: 拆分：
	* 1. rtsp://  代表匹配 rtsp:// 开头的字符串，
	* 2. %[^:]  代表匹配任意个字符，直到遇到 : 这个符号  【示例中就是 127.0.0.1， 因为下一个字符就是 : 了】
	* 3. :    代表匹配以 : 这个符号结尾
	*/
	sscanf(url, "rtsp://%[^:]:", localIp);
	// 构造sdp数据
	sprintf(sdp, "v=0\r\n"
		"o=- 9%ld 1 IN IP4 %s\r\n"
		"t=0 0\r\n"
		"a=control:*\r\n"
		"m=video 0 RTP/AVP 96\r\n"
		"a=rtpmap:96 H264/90000\r\n"
		"a=control:track0\r\n"
		"m=audio 1 RTP/AVP 97\r\n"
		"a=rtpmap:97 mpeg4-generic/44100/2\r\n"
		"a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1210;\r\n"
		"a=control:track1\r\n",
		time(NULL), localIp);
	// 构造总响应数据
	sprintf(result, "RTSP/1.0 200 OK\r\n"
		"CSeq: %d\r\n"
		"Content-Base: %s\r\n"
		"Content-type: application/sdp\r\n"
		"Content-length: %zu\r\n\r\n"
		"%s",
		cseq,
		url,
		strlen(sdp),
		sdp);
	return 0;
}

// 处理SETUP请求，构建响应数据到result中
 int handleCmd_SETUP(char* result, int cseq, int clientRtpPort)
{
	sprintf(result, "RTSP/1.0 200 OK\r\n"
		"CSeq: %d\r\n"
		"Transport: RTP/AVP;unicast;client_port=%d-%d;server_port=%d-%d\r\n"
		"Session: 66334873\r\n"
		"\r\n",
		cseq,
		clientRtpPort,
		clientRtpPort + 1,
		SERVER_RTP_PORT,
		SERVER_RTCP_PORT);
	return 0;
}

// 处理PLAY请求，构建响应数据到result中
 int handleCmd_PLAY(char* result, int cseq)
{
	/// npt 是流已经播放了的时间
	/// Session 是会话id
	sprintf(result, "RTSP/1.0 200 OK\r\n"
		"CSeq: %d\r\n"
		"Range: npt=0.000-\r\n"
		"Session: 66334873; timeout=10\r\n\r\n",
		cseq);
	return 0;
}

// 判断数据前三个字节是否是 0x 00 00 01 [NALU的startCode]
 int startCode3(char* buf)
{
	if (buf[0] == 0 && buf[1] == 0 && buf[2] == 1)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

// 判断数据前四个字节是否是 0x 00 00 00 01 [NALU的startCode]
 int startCode4(char* buf)
{
	if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 1)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

// 返回一个指针，指向下一个 startCode 开始的第一个字节的位置
 char* findNextStartCode(char* buf, int len)
{
	// 一个 startCode 至少三个字节，如果 buf 连三个字节都没有，那肯定没有 startCode
	if (len < 3)
	{
		return NULL;
	}
	// 这里遍历到 len - 3 [用的 < 符号，实际上是4个字节] 是因为 startCode4 至少需要 4 个字节才行
	for (int i = 0; i < len - 3; i++)
	{
		if (startCode3(buf) || startCode4(buf))
		{
			return buf;
		}
		buf++;
	}
	// 如果所有的 startCode4 都不满足，那么还剩下最后一个 startCode3 可以判断
	if (startCode3(buf))
	{
		return buf;
	}

	return NULL;
}

// 从文件中读取 size 个字节的数据到 frame 中
 int getFrameFromH264File(FILE* fp, char* frame, int size)
{
	int rSize, frameSize;
	char* nextStartCode;

	if (!fp)
	{
		return -1;
	}

	rSize = fread(frame, 1, size, fp);

	// 如果读取出来不是 NALU的 startCode，代表这个H264文件的内容有问题
	if (!startCode3(frame) && !startCode4(frame))
	{
		return -1;
	}

	// 找到下一个 startCode 的位置
	nextStartCode = findNextStartCode(frame + 3, rSize - 3);
	// 如果没找到，那么代表这个H264文件的内容有问题[当然，有可能是文件读取完毕了，没有下一个了]
	if (!nextStartCode)
	{
		return -1;
	}
	else
	{
		// 下一个 startCode的位置 减去 这一个 startCode的位置 就能得出这个 startCode 的长度了
		frameSize = nextStartCode - frame;
		/*
		* 由于刚刚读取数据多了，所以需要将文件的游标移动回去，本次只读取一个 NALU 大小的数据就够了
		* [frameSize - rSize 是负数，所以文件游标会向左移动]
		*/
		fseek(fp, frameSize - rSize, SEEK_CUR);
	}
	// 返回本次读取的真实NALU大小
	return frameSize;
}

// 通过RTP包发送H264数据
 int rtpSendH264Frame(int serverRtpSockfd, const char* ip, int16_t port,
	struct RtpPacket* rtpPacket, char* frame, uint32_t frameSize)
{
	uint8_t naluType = frame[0]; //NALU的第一个字节
	int sendBytes = 0; //记录本次已经发送出去的字节大小
	int ret = 0;

	printf("H264_Frame_Size=%d \n", frameSize);

	// 如果NALU长度小于RTP的最大包长：单一NALU单元模式
	if (frameSize <= RTP_MAX_PKT_SIZE)
	{
		//*   0 1 2 3 4 5 6 7 8 9
		//*  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		//*  |F|NRI|  Type   | a single NAL unit ... |
		//*  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		// 将读取的NALU数据复制到RTP包中
		memcpy(rtpPacket->payload, frame, frameSize);
		// 通过udp发送RTP包数据
		ret = rtpSendPacketOverUdp(serverRtpSockfd, ip, port, rtpPacket, frameSize);
		if (ret < 0)
		{
			return -1;
		}
		// 序号+1，代表又成功发送了一次RTP包
		rtpPacket->rtpHeader.seq++;
		// 记录本次发送出去的字节大小
		sendBytes += ret;
		// 如果是 SPS、PPS则不需要添加时间戳  0x1F：0001 1111 即后五位，即Type
		if ((naluType & 0x1F) == 7 || (naluType & 0x1F) == 8)
		{
			goto out;
		}
	}
	// NALU长度大于最大的包长：分片模式
	else
	{
		 //*  0                   1                   2
         //*  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
         //* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         //* | FU indicator  |   FU header   |   FU payload   ...  |
         //* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+



         //*     FU Indicator
         //*    0 1 2 3 4 5 6 7
         //*   +-+-+-+-+-+-+-+-+
         //*   |F|NRI|  Type   |
         //*   +---------------+



         //*      FU Header
         //*    0 1 2 3 4 5 6 7
         //*   +-+-+-+-+-+-+-+-+
         //*   |S|E|R|  Type   |
         //*   +---------------+
		int pktNum = frameSize / RTP_MAX_PKT_SIZE; // 计算一共能有几个完整的包
		int remainPktSize = frameSize % RTP_MAX_PKT_SIZE; //计算剩余这个包的数据大小
		int pos = 1; // 分片模式中，RTP传输payload的时候直接会构建一个和NALU的第一个字节格式相同的数据，故不需要NALU的第一个字节。

		for (int i = 0; i < pktNum; i++)
		{
			// payload的第一个字节的前三位使用NALU第一个字节的前三位： F|NRI， 但是 type需要修改为 28，即FU-A
			rtpPacket->payload[0] = (naluType & 0x60) | 28;
			// payload的第二个字节的后五位使用NALU第一个字节的后五位： 即type
			rtpPacket->payload[1] = naluType & 0x1F;
			if (i == 0)
			{
				rtpPacket->payload[1] |= 0x80; // NALU分包的第一个包
			}
			// 如果是最后一个包
			else if (remainPktSize == 0 && i == pktNum - 1)
			{
				rtpPacket->payload[1] |= 0x40; // NALU分包的最后一个包
			}
			// 将这一次可以传输的NALU数据复制到payload中
			memcpy(rtpPacket->payload + 2, frame + pos, RTP_MAX_PKT_SIZE);
			// 通过udp发送RTP包数据
			ret = rtpSendPacketOverUdp(serverRtpSockfd, ip, port, rtpPacket, RTP_MAX_PKT_SIZE + 2);
			if (ret < 0)
			{
				return -1;
			}
			// 序号+1，代表又成功发送了一次RTP包
			rtpPacket->rtpHeader.seq++;
			// 记录本次发送出去的字节大小
			sendBytes += ret;
			// 更新NALU游标位置，此时已经从 NALU 中读取了 RTP_MAX_PKT_SIZE 字节的数据出去，下一次要从新的位置开始读取
			pos += RTP_MAX_PKT_SIZE;
		}
		// 如果有剩余不完整的包，那么for循环中就不是最后一个包，这里才是最后一个包
		if (remainPktSize > 0)
		{
			// payload的第一个字节的前三位使用NALU第一个字节的前三位： F|NRI， 但是 type需要修改为 28，即FU-A
			rtpPacket->payload[0] = (naluType & 0x60) | 28;
			// payload的第二个字节的后五位使用NALU第一个字节的后五位： 即type
			rtpPacket->payload[1] = naluType & 0x1F;
			rtpPacket->payload[1] |= 0x40; // NALU分包的最后一个包
			// 将这一次可以传输的NALU数据复制到payload中
			memcpy(rtpPacket->payload + 2, frame + pos, remainPktSize);
			// 通过udp发送RTP包数据
			ret = rtpSendPacketOverUdp(serverRtpSockfd, ip, port, rtpPacket, remainPktSize + 2);
			if (ret < 0)
			{
				return -1;
			}
			// 序号+1，代表又成功发送了一次RTP包
			rtpPacket->rtpHeader.seq++;
			// 记录本次发送出去的字节大小
			sendBytes += ret;
		}
	}
	// 记录发送了的总时间增加
	rtpPacket->rtpHeader.timestamp += 90000 / 25;
out:
	return sendBytes;
}

// AAC的标识头[7个字节]
struct AdtsHeader
{
	// 固定头信息，fixed_header : 28bit
	uint32_t syncword;			//12 bit 同步字 '1111 1111 1111'，一个ADTS帧的开始
	uint8_t id;					//1 bit 0代表MPEG-4, 1代表MPEG-2
	uint8_t layer;				//2 bit 必须为0
	uint8_t protectionAbsent;	//1 bit 1代表没有CRC，0代表有CRC
	uint8_t profile;			//1 bit AAC级别（MPEG-2 AAC中定义了3种profile，MPEG-4 AAC中定义了6种profile）
	uint8_t samplingFreqIndex;	//4 bit 采样率
	uint8_t privateBit;			//1bit 编码时设置为0，解码时忽略
	uint8_t channelCfg;			//3 bit 声道数量
	uint8_t originalCopy;		//1bit 编码时设置为0，解码时忽略
	uint8_t home;				//1 bit 编码时设置为0，解码时忽略

	// 可变头信息，variable_header : 28bit
	uint8_t copyrightIdentificationBit;		//1 bit 编码时设置为0，解码时忽略
	uint8_t copyrightIdentificationStart;	//1 bit 编码时设置为0，解码时忽略
	uint32_t aacFrameLength;				//13 bit 一个ADTS帧的长度包括ADTS头和AAC原始流
	uint32_t adtsBufferFullness;			//11 bit 缓冲区充满度，0x7FF说明是码率可变的码流，不需要此字段。CBR可能需要此字段，不同编码器使用情况不同。这个在使用音频编码的时候需要注意。
	/* number_of_raw_data_blocks_in_frame
	 * 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧
	 * 所以说number_of_raw_data_blocks_in_frame == 0
	 * 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
	 */
	uint8_t numberOfRawDataBlockInFrame;	//2 bit
};

// 解析 in 中的数据，将 in 中的数据解析成一个 AdtsHeader 写入 res 中
 int parseAdtsHeader(uint8_t* in, struct AdtsHeader* res)
{
	memset(res, 0, sizeof(*res));
	// 1111 1111 1111 开头则代表是一个Adts， 0xFF 是 1111 1111，0xF0 是 1111 0000
	if (in[0] == 0xFF && ((in[1] & 0xF0) == 0xF0))
	{
		/*
		* res->syncword 的数据是固定的，接下来我们也不会用，故这里赋值与否都无所谓
		* 位运算就不用讲了，对比 AdtsHeader 看就行了。
		* res->id是第13位，in[1]是第8~15位，& 0x08[0000 0100] 就只会保留第 13 位的数据,再 >> 3,就得到了这一位的数据
		*/
		res->id = (in[1] & 0x08) >> 3;
		res->layer = (in[1] & 0x06) >> 1;
		res->protectionAbsent = in[1] & 0x01;
		res->profile = (in[2] & 0xc0) >> 6;
		res->samplingFreqIndex = (in[2] & 0x3c) >> 2;
		res->privateBit = (in[2] & 0x02) >> 1;
		res->channelCfg = (((in[2] & 0x01) << 2) | ((in[3] & 0xc0) >> 6));
		res->originalCopy = (in[3] & 0x20) >> 5;
		res->home = (in[3] & 0x10) >> 4;
		res->copyrightIdentificationBit = (in[3] & 0x08) >> 3;
		res->copyrightIdentificationStart = (in[3] & 0x04) >> 2;

		res->aacFrameLength = ((in[3] & 0x03) << 11) |
			((in[4] & 0xFF) << 3) |
			(in[5] & 0xE0) >> 5;

		res->adtsBufferFullness = (in[5] & 0x1f) << 6 |
			(in[6] & 0xfc) >> 2;
		res->numberOfRawDataBlockInFrame = in[6] & 0x03;
		return 0;
	}
	else
	{
		cout << "failed to parse adts header" << endl;
		return -1;
	}
}

// 通过RTP包发送AAC数据
int rtpSendAACFrame(int serverRtpSockfd, const char* ip, int16_t port,
	struct RtpPacket* rtpPacket, uint8_t* frame, uint32_t frameSize)
{
	int ret = 0;
	printf("AAC_Frame_Size=%d \n", frameSize);
	// RTP打包AAC时payload的前四个字节有特定意义
	rtpPacket->payload[0] = 0x00;
	rtpPacket->payload[1] = 0x10;
	/*
	* 0x1FE0  0001 1111 1110 0000  [高8位]
	* 0x1F    0000 0000 0001 1111  [低5位]
	*/
	rtpPacket->payload[2] = (frameSize & 0x1FE0) >> 5;// 高8位
	rtpPacket->payload[3] = (frameSize & 0x1F) << 3; // 低5位
	// 将aac的数据复制到rtp的payload中
	memcpy(rtpPacket->payload + 4, frame, frameSize);
	// 通过UDP发送RTP数据
	ret = rtpSendPacketOverUdp(serverRtpSockfd, ip, port, rtpPacket, frameSize + 4);
	if (ret < 0)
	{
		cout << "faild to send rtp packet" << endl;
		return -1;
	}
	// rtp发送序号加1
	rtpPacket->rtpHeader.seq++;
	/*
	 * 如果采样频率是44100
	 * 一般AAC每个1024个采样为一帧
	 * 所以一秒就有 44100 / 1024 = 43帧
	 * 时间增量就是 44100 / 43 = 1025
	 * 一帧的时间为 1 / 43 = 23ms
	 */
	// rtp累计单位时间增加

	rtpPacket->rtpHeader.timestamp += 1025;

 	return 0;
}


// 处理客户端的交互
 void doClient(int clientSockfd, const char* clientIp, int clientPort)
{
	char* recvBuf = (char*)malloc(BUF_MAX_SIZE);
	char* sendBuf = (char*)malloc(BUF_MAX_SIZE);
	int recvLen;

	int serverRtpSockfd = -1, serverRtcpSockfd = -1;

	char method[40] = {'\0'};
	char url[100] = { '\0' };
	char version[40] = { '\0' };
	int CSeq = 0;
	int clientVideoRtpPort = 0, clientVideoRtcpPort = 0;
	int clientAudioRtpPort = 0, clientAudioRtcpPort = 0;
	const char* sep = "\n";
	while (true)
	{
		// vs的warn提醒
		if (!recvBuf || !sendBuf)
		{
			break;
		}
		// 阻塞等待接受消息，本次接受的最大字节数为1MB，即 SOCKET_BUF_MAX_SIZE
		recvLen = recv(clientSockfd, recvBuf, BUF_MAX_SIZE, 0);
		// 返回非正数代表无法获取到数据了，即断开连接
		if (recvLen <= 0)
		{
			break;
		}
		// char接受，需要拼接结束符
		recvBuf[recvLen] = '\0';
		printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
		printf("%s recvBuf= %s \n", __FUNCTION__, recvBuf);

		// 将 recvBuf 按照 \n 进行切分，得到一个 \n 前的字符串 [如果切分失败，则返回null]，
		// 下一次调用 strtok(null, sep)，则是获取下一个 \n 前面的字符串，反复调用strtok(null, sep)直到返回null
		char* line = strtok(recvBuf, sep);
		while (line)
		{
			// strstr(line, "OPTIONS")：判断line中是否包含 "OPTIONS"字符串，如果包含则返回该字符串，否则返回null
			// 如果这一行是请求方法信息
			if (strstr(line, "OPTIONS")
				|| strstr(line, "DESCRIBE")
				|| strstr(line, "SETUP")
				|| strstr(line, "PLAY"))
			{
				// 解析这一行数据，数据格式一般是：
				// [请求方式 请求地址 版本号]
				// 示例：OPTIONS rtsp://127.0.0.1:8554 RTSP/1.0
				if (sscanf(line, "%s %s %s \r\n", method, url, version) != 3)
				{
					// 格式错误，应该error
				}
			}
			// 如果这一行是序列号信息
			else if (strstr(line, "CSeq"))
			{
				// 解析这一行数据，数据格式一般是:
				// CSeq: {序列号}
				// 示例：CSeq: 1
				if (sscanf(line, "CSeq: %d \r\n", &CSeq) != 1)
				{
					// 格式错误，应该error
				}
			}
			// strncmp(s1,s2,n) 判断s1和s2的前n个字符是否相等，相等则返回0
			// 如果这一行是传输方式信息
			else if (!strncmp(line, "Transport:", strlen("Transport:")))
			{
				/*
				* 解析这一行数据，数据格式一般是：
				* Transport: RTP/AVP/UDP;unicast;client_port={客户端的RTP端口号}-{客户端的RTCP端口号}
				* 示例：Transport: RTP/AVP/UDP;unicast;client_port=13358-13359
				*/
				// 如果是视频的SETTUP
				if (strstr(url, "track0"))
				{
					if (sscanf(line, "Transport: RTP/AVP/UDP;unicast;client_port=%d-%d\r\n", &clientVideoRtpPort, &clientVideoRtcpPort) != 2)
					{
						// 格式错误，应该error
						cout << "parse Transport error" << endl;
					}
				}
				// 如果是音频的SETTUP
				else if (strstr(url, "track1"))
				{
					if (sscanf(line, "Transport: RTP/AVP/UDP;unicast;client_port=%d-%d\r\n", &clientAudioRtpPort, &clientAudioRtcpPort) != 2)
					{
						// 格式错误，应该error
						cout << "parse Transport error" << endl;
					}
				}
				else
				{
					// 格式错误，应该error
					cout << "parse Transport error" << endl;
				}
			}
			// 获取下一行的数据[recvBuf中下一个 \n 前的数据]
			line = strtok(NULL, sep);
		}

		// 根据客户端本次传输的请求方式，来构造服务器需要返回[响应]的数据
		if (!strcmp(method, "OPTIONS"))
		{
			// 构造客户端OPTIONS请求方式时服务器需要响应的数据
			if (handleCmd_OPTIONS(sendBuf, CSeq))
			{
				cout << "failed to handle options" << endl;
				break;
			}
		}
		else if (!strcmp(method, "DESCRIBE"))
		{
			// 构造客户端DESCRIBE请求方式时服务器需要响应的数据
			if (handleCmd_DESCRIBE(sendBuf, CSeq, url))
			{
				cout << "failed to handle describe" << endl;
				break;
			}
		}
		else if (!strcmp(method, "SETUP"))
		{
			// 此时应该建立RTP和RTCP的套接字准备传输数据了
			if (serverRtpSockfd == -1 && serverRtcpSockfd == -1)
			{
				// 创建RTP和RTCP的套接字
				serverRtpSockfd = createUdpSocket();
				serverRtcpSockfd = createUdpSocket();
				if (serverRtpSockfd < 0 || serverRtcpSockfd < 0)
				{
					cout << "failed to create udp socket" << endl;
					break;
				}

				// 绑定端口
				if (bindSocketAddr(serverRtpSockfd, SERVER_IP, SERVER_RTP_PORT) < 0
					|| bindSocketAddr(serverRtcpSockfd, SERVER_IP, SERVER_RTCP_PORT) < 0)
				{
					cout << "failed to bind udp addr" << endl;
					break;
				}
			}
			// 构造客户端SETUP请求方式时服务器需要响应的数据
			// 如果是视频的SETTUP
			if (strstr(url, "track0"))
			{
				if (handleCmd_SETUP(sendBuf, CSeq, clientVideoRtpPort))
				{
					cout << "failed to handle setup" << endl;
					break;
				}
			}
			// 如果是音频的SETTUP
			else if (strstr(url, "track1"))
			{
				if (handleCmd_SETUP(sendBuf, CSeq, clientAudioRtpPort))
				{
					cout << "failed to handle setup" << endl;
					break;
				}
			}
			// 其他情况，当然我们这种判断肯定有问题，不应该根据3，4来判断，应该去解析才对
			else
			{
				// 格式错误，应该error
				cout << "parse Transport error" << endl;
			}
		}
		else if (!strcmp(method, "PLAY"))
		{
			// 构造客户端PLA Y请求方式时服务器需要响应的数据
			if (handleCmd_PLAY(sendBuf, CSeq))
			{
				cout << "failed to handle play" << endl;
				break;
			}
		}
		else
		{
			printf("未定义的method = %s\n", method);
			break;
		}


		printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
		printf("%s sendBuf= %s \n", __FUNCTION__, sendBuf);
		// 发送数据给客户端
		send(clientSockfd, sendBuf, strlen(sendBuf), 0);

		// 开始播放，发送RTP包
		if (!strcmp(method, "PLAY"))
		{
			printf("start play\n client ip:%s \n client port: %d\n", clientIp, clientPort);
			//while (1)

			//{
			//	Sleep(40);
			//}
			std::thread t1([&]() {
				int frameSize, startCode;
				char* frame = (char*)malloc(BUF_MAX_SIZE);
				struct RtpPacket* rtpPacket = (struct RtpPacket*)malloc(BUF_MAX_SIZE);
				// 模拟本地读取数据
				FILE* fp = fopen(H264_FILE_NAME, "rb");
				if (!fp)
				{
					printf("打开视频文件 %s 失败\n", H264_FILE_NAME);
					return ;
				}

				/*
				*  0x88923423 是SSRC，标识唯一即可。我这里是随便写的一个值，没有意义，只是为了唯一，也可以用rand()生成
				*/
				// 初始化rtpPacket中的标识头信息 --- 只会init一次，后续只会填充/修改 payload 数据
				rtpHeaderInit(rtpPacket, RTP_VERSION, 0, 0, 0, 0, RTP_PAYLOAD_TYPE_H264,
					0, 0, 0x88923423);

				// 开始循环读取视频数据
				while (true)
				{
					// 从文件中读取一个NALU的数据
					frameSize = getFrameFromH264File(fp, frame, BUF_MAX_SIZE);
					if (frameSize < 0)
					{
						printf("读取视频文件 %s 结束, frameSize=%d \n", H264_FILE_NAME, frameSize);
						break;
					}
					// 获取 startCode 的长度
					if (startCode3(frame))
					{
						startCode = 3;
					}
					else
					{
						startCode = 4;
					}
					/*
					* RTP发送的时候不需要携带 startCode，因为一个RTP就是一个完整的NALU数据。
					* 应该说RTP能区分出一个完整的NALU数据，可见单个打包模式、 FU 模式，它们都能区分出来完整的NALU数据
					*/
					frameSize -= startCode;
					// 发送本次NALU数据
					rtpSendH264Frame(serverRtpSockfd, clientIp, clientVideoRtpPort,
						rtpPacket, frame + startCode, frameSize);
					// todo：应该多个判断，比如 SPS 、 PPS 是不需要睡眠的
					Sleep(40);
				}
				// 释放内存
				free(frame);
				free(rtpPacket);
				});
			std::thread t2([&]() {
				// return;
				struct AdtsHeader adtsHeader;
				struct RtpPacket* rtpPacket = (struct RtpPacket*)malloc(BUF_MAX_SIZE);
				uint8_t* frame = (uint8_t*)malloc(BUF_MAX_SIZE);
				// 这里不像 h264 一样记录读取的数据大小，是因为adtsHeader中已经记录每一帧的大小了
				int ret = 0;
				// 模拟本地读取数据
				FILE* fp = fopen(AAC_FILE_NAME, "rb");
				if (!fp)
				{
					printf("读取音频文件 %s 失败\n", AAC_FILE_NAME);
					return ;
				}
				/*
				*  0x88923424 是SSRC，标识唯一即可。我这里是随便写的一个值，没有意义，只是为了唯一，也可以用rand()生成
				*/
				// 初始化rtpPacket中的标识头信息 --- 只会init一次，后续只会填充/修改 payload 数据
				rtpHeaderInit(rtpPacket, RTP_VERSION, 0, 0, 0, 0, RTP_PAYLOAD_TYPE_AAC, 0, 0, 0x88923424);
				while (true)
				{
					// 读取 7 个字节的数据 [adtsHeader]
					ret = fread(frame, 1, 7, fp);
					if (ret <= 0)
					{
						printf("读取音频文件 %s 结束, ret=%d \n", AAC_FILE_NAME, ret);
						break;
					}
					// 从字节frame解析一个完整的adtsHeader出来
					if (parseAdtsHeader(frame, &adtsHeader) < 0)
					{
						cout << "parseAdtsHeader error" << endl;
						break;
					}
					// 读取一帧adts的es数据[也许不止一帧，可能是n帧，但可以确保读取每一帧都是完整的es数据]
					ret = fread(frame, 1, adtsHeader.aacFrameLength - 7, fp);
					// 发送本次的AAC的数据
					rtpSendAACFrame(serverRtpSockfd, clientIp, clientAudioRtpPort, rtpPacket, frame,
						adtsHeader.aacFrameLength - 7);
					// 一个音频帧23s，但不需要睡眠23，因为数据没连续接上会导致噪音
					Sleep(1);
				}
				// 释放内存
				free(frame);
				free(rtpPacket);
			});

			// 等待线程结束
			t1.join();
			t2.join();

			break;
		}
		// 重新初始化数据
		memset(method, 0, sizeof(method) / sizeof(char));
		memset(url, 0, sizeof(url) / sizeof(char));
		CSeq = 0;
	}
	// 关闭客户端的套接字连接
	closesocket(clientSockfd);
	free(recvBuf);
	free(sendBuf);
}

int main()
{
	// 存储windows的socket的相关信息
	WSADATA wsaData;
	// 初始化windows的socket的dll
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		cout << "PC Server Socket Start Up Error" << endl;
	}
	// 创建套接字
	int serverSockfd = createTcpSocket();
	if (serverSockfd < 0)
	{
		// 清理windows的socket的dll，释放相关资源
		WSACleanup();
		cout << "faild to create tcp socket" << endl;
		return -1;
	}
	// 将套接字绑定到指定的ip、端口
	if (bindSocketAddr(serverSockfd, SERVER_IP, SERVER_PORT) < 0)
	{
		cout << "faild to bind tcp addr" << endl;
		return -1;
	}
	// 启动套接字的监听状态，开始监听端口【10代表最多允许10个客户端连接排队等待】
	if (listen(serverSockfd, 10) < 0)
	{
		cout << "faild to listen" << endl;
		return -1;
	}
	printf("RtspServer rtsp://%s:%d\n", SERVER_IP, SERVER_PORT);

	while (true)
	{
		int clientSockfd;
		char clientIp[40];
		int clientPort;
		// 监听客户端的连接
		clientSockfd = acceptClient(serverSockfd, clientIp, &clientPort);
		if (clientSockfd < 0)
		{
			cout << "faild to accept client" << endl;
			return -1;
		}
		printf("accept client:\t clientIp: %s \t clientPort:%d\n", clientIp, clientPort);
		// 处理客户端交互【目前是阻塞处理，后续需要修改】
		doClient(clientSockfd, clientIp, clientPort);
	}

	// 关闭客户端和服务器的套接字
	closesocket(serverSockfd);
	system("pause");
	return 0;
}